<?php

namespace App\Service\OpenShop\Feishu;


use App\Enums\BaseErrorCode;
use App\Enums\Contract\ContractErrCode;
use App\Enums\OpenShop\InvestmentPromotion\ContractStatusEnum;
use App\Enums\OpenShop\InvestmentPromotion\ErrCode;
use App\Enums\OpenShop\InvestmentPromotion\MainProcessEnum;
use App\Enums\OpenShop\InvestmentPromotion\ShopManualEnum;
use App\Enums\OpenShop\InvestmentPromotion\SignOrderEnum;
use App\Enums\OpenShop\InvestmentPromotion\UserBaseInfoEnum;
use App\Enums\OpenShop\InvestmentPromotion\UserContractEnum;
use App\Enums\OpenShop\MissionTemplateEnum;
use App\Events\OpenShop\OpenShopProcessEvent;
use App\Events\OpenShop\OrderSignedEvent;
use App\Exceptions\Custom\CustomHttpResponseException;
use App\Exceptions\Custom\ResponseHttpException;
use App\Library\FeiShu\SendFs;
use App\Library\Rms\RmsShopApi;
use App\Models\Appraise\AppraiseModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopContractTemplateModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopLocationModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopShopManual;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderLogModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopSignOrderPayHistoryModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserBaseInfoModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserContractModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserExtContractModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserIdentityCardModel;
use App\Models\OpenShop\SiteLocation\OpenShopSiteLocationModel;
use App\Remote\Rms\RmsShopRemote;
use App\Service\BaseService;
use App\Service\OpenShop\OrderService;
use App\Service\OpenShop\SiteLocation\SiteLocationService;
use App\Service\Renew\RenewOrderService;
use App\Service\WorkOrder\Appraise\NotifyService;
use App\Support\ChangeSupport;
use Closure;
use Exception;
use Faker\Generator;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Kuafu\File\PrivateFileUtil;
use Kuafu\Qiyuesuo\bean\Category;
use Kuafu\Qiyuesuo\bean\Contract;
use Kuafu\Qiyuesuo\bean\Signatory;
use Kuafu\Qiyuesuo\bean\Stamper;
use Kuafu\Qiyuesuo\bean\TemplateParam;
use Kuafu\Qiyuesuo\bean\User;
use Kuafu\Qiyuesuo\bean\UserAuthInfo;
use Kuafu\Qiyuesuo\request\ContractCompanySignRequest;
use Kuafu\Qiyuesuo\request\ContractDetailRequest;
use Kuafu\Qiyuesuo\request\ContractDraftRequest;
use Kuafu\Qiyuesuo\request\ContractInvalidRequest;
use Kuafu\Qiyuesuo\request\ContractNoticeRequest;
use Kuafu\Qiyuesuo\request\ContractShorturlRequest;
use Kuafu\Qiyuesuo\request\ContractSignInvalidRequest;
use Kuafu\Qiyuesuo\request\DocumentDownloadRequest;
use Kuafu\Qiyuesuo\sdk\SDKClient;
use Kuafu\Qiyuesuo\utils\CryptUtils;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\HttpFoundation\Response;

/**
 * @author Green Leaf <786407418@qq.com>
 */
class UserExtContractService extends BaseService
{

    public static ?string $orderNo = null;

    /**
     * 签署公章位置配置
     *
     *
     * @return \array[][]
     */
    public static function getSignPlace(): array
    {
        return [
            [
                [
                    'sealId'  => config('qiyuesuo.tj_seal_id'),
                    'page'    => 1,
                    'offsetX' => 0.2,
                    'offsetY' => 0.2
                ]
            ],
            [
                [
                    'sealId'  => config('qiyuesuo.tj_seal_id'),
                    'page'    => 1,
                    'offsetX' => 0.2,
                    'offsetY' => 0.2
                ]
            ],
            [
                [
                    'sealId'  => config('qiyuesuo.tj_seal_id'),
                    'page'    => 1,
                    'offsetX' => 0.2,
                    'offsetY' => 0.2
                ]
            ]
        ];
    }

    /**
     * 合同
     *
     * @var Contract
     */
    private Contract $contract;


    /**
     * sdkClient
     *
     * @var SDKClient
     */
    private SDKClient $sdkClient;

    public function __construct()
    {
        $this->sdkClient = new SDKClient(
            config('qiyuesuo.wps_key'),
            config('qiyuesuo.wps_secret'),
            config('qiyuesuo.url'),
        );
    }

    /**
     * @return SDKClient
     */
    public function getSdkClient(): SDKClient
    {
        return $this->sdkClient;
    }

    /**
     * @return $this
     */
    public function generateContract(): UserExtContractService
    {
        $this->contract = new Contract();
        return $this;
    }

    /**
     * 获取合同版本对应的参数
     *
     * @param int $contactVersion 合同模板的版本
     * @param int $contractors
     * @param int $mode 加盟模式 1-传统模式 2分账模式
     * @return string[]
     */
    public static function getContactConfig(
        int $contactVersion = 1,
        int $contractors = UserContractEnum::CONTRACT_PERSONAL,
        int $mode = OpenShopContractTemplateModel::MODE_1
    ) {
        $return = [
            'categoryId'   => '',
            'notifySecret' => ''
        ];

        $suffix = "";//模式 配置后缀
        if ($mode == OpenShopContractTemplateModel::MODE_2) {//分账模式
            $suffix = "_mode2";
        }
        if ($contractors == UserContractEnum::CONTRACT_PERSONAL) {
            // 个人
            switch ($contactVersion) {
                case 1:
                    $return['categoryId']   = config('qiyuesuo.category_id' . $suffix);
                    $return['notifySecret'] = config('qiyuesuo.notify_secret' . $suffix);
                    break;
                case 2:
                    $return['categoryId']   = config('qiyuesuo.category_id_v2' . $suffix);
                    $return['notifySecret'] = config('qiyuesuo.notify_secret_v2' . $suffix);
                    break;
            }


        } else {
            // 公司
            switch ($contactVersion) {
                case 1:
                case 2:
                    $return['categoryId']   = config('qiyuesuo.category_company_id_v2' . $suffix);
                    $return['notifySecret'] = config('qiyuesuo.notify_company_secret_v2' . $suffix);
                    break;
            }

        }

        return $return;
    }


    /**
     * @param string $bizId 业务ID；一个合同对应一个bizId，不能重复
     * @param string $subject
     * @param string $description 合同描述
     * @param bool $ordinal 是否顺序签署；默认为true
     * @param bool $send 是否发起合同；发起合同后不能再进行添加文档、指定签署位置等操作
     * @return UserExtContractService
     */
    public function setContractMainBody(
        string $bizId,
        string $subject,
        string $description,
        bool $ordinal = true,
        bool $send = true
    ): UserExtContractService {
        $this->contract->setBizId($bizId);
        $this->contract->setSubject($subject);
        $this->contract->setDescription($description);
        $this->contract->setOrdinal($ordinal);
        $this->contract->setSend($send);
        return $this;
    }

    /**
     * 绑定业务分类
     *
     * @param string $categoryId 业务分类；默认为云平台的“默认业务分类
     */
    public function bindCategory(string $categoryId): UserExtContractService
    {
        //绑定业务
        $category = new Category();
        $category->setId($categoryId);
        $this->contract->setCategory($category);
        return $this;
    }

    /**
     * 设置签署方信息
     *
     * @param array $signatoryConfig
     * @return UserExtContractService
     */
    public function setSignatory(array $signatoryConfig = []): UserExtContractService
    {
        $signatoryGroup = [];
        collect($signatoryConfig)->each(function ($v) use (&$signatoryGroup) {
            //签署方 - 发起方
            $signatory = new Signatory();
            $signatory->setTenantType($v->tenantType);
            $signatory->setTenantName($v->tenantName);
            $signatory->setSerialNo($v->serialNo);

            if (!empty($v->userAuthInfo)) {
                $userAuthInfo = new UserAuthInfo();
                $userAuthInfo->setIdCardNo($v->userAuthInfo->idCardNo);
                $signatory->setUserAuthInfo($userAuthInfo);
            }

            if (!empty($v->receiver)) {
                $receiver = new User();
                $receiver->setContact($v->receiver->contact);
                $receiver->setContactType($v->receiver->contactType);
                $signatory->setReceiver($receiver);
            }

            array_push($signatoryGroup, $signatory);
        });
        $this->contract->setSignatories($signatoryGroup);
        return $this;
    }


    /**
     * @param array $params
     * @return UserExtContractService
     */
    public function templateRender(array $params = []): UserExtContractService
    {
        $templateParams = array();
        collect($params)->each(function ($v, $k) use (&$templateParams) {
            /**填写模板参数**/
            $templateParam1 = new TemplateParam();
            $templateParam1->setName($k);
            $templateParam1->setValue($v);

            array_push($templateParams, $templateParam1);
        });
        //渲染模版
        $this->contract->setTemplateParams($templateParams);
        return $this;
    }


    /**
     * @return mixed|string|null
     */
    public function contractDraftRequest()
    {
        return $this->sdkClient->service(new ContractDraftRequest($this->contract));
    }

    /**
     * 签署公章
     *
     * @param string $bizId
     * @param string $contractId
     * @param string|null $sealId
     * @param array|null $documents
     * @return mixed|string|null
     */
    public function companySign(string $bizId, string $contractId, string $sealId = null, array $documents = null)
    {
        $contractCompanySignRequest = new ContractCompanySignRequest();
        $contractCompanySignRequest->setBizId($bizId);
        $contractCompanySignRequest->setContractId($contractId);
        if ($sealId) {
            $contractCompanySignRequest->setSealId($sealId);
        }
        $stamperGroup = array();
        if (!empty($documents)) {
            collect($documents)->each(function ($document, $k) use (&$stamperGroup) {
                collect(self::getSignPlace()[$k])->each(function ($v) use ($document, &$stamperGroup) {
                    /**公章签署**/
                    $stamper = new Stamper();
                    $stamper->setType('COMPANY');
                    $stamper->setDocumentId($document['id']);
                    $stamper->setSealId($v['sealId']);
                    $stamper->setPage($v['page']);
                    $stamper->setOffsetX($v['offsetX']);
                    $stamper->setOffsetY($v['offsetY']);

                    array_push($stamperGroup, $stamper);
                });
            });
        }
        $contractCompanySignRequest->setStampers($stamperGroup);
        return $this->sdkClient->service($contractCompanySignRequest);
    }

    /**
     * 获取短链接
     *
     * @param string $bizId
     * @return mixed|string|null
     */
    public function getContractShortUrl(string $bizId)
    {
        $baseRequest = new ContractShorturlRequest();
        $baseRequest->setBizId($bizId);
        return $this->sdkClient->service($baseRequest);
    }

    /**
     * 获取短链接
     *
     * @param string $extContractId
     * @return mixed|string|null
     */
    public function getContractShortUrlByExtContractId(string $extContractId)
    {
        $baseRequest = new ContractShorturlRequest();
        $baseRequest->setContractId($extContractId);
        return $this->sdkClient->service($baseRequest);
    }

    /**
     * @param array $response
     * @param string $title
     * @return mixed
     * @throws Exception
     */
    public static function handleResponse(array $response, string $title)
    {
        if (!empty($response) && $response['code'] == 0) {
            return $response['result'] ?? [];
        }

        try {
            OpenShopUserContractModel::query()
                                     ->where("orderNo", self::$orderNo)
                                     ->where("contractExtNo", "")
                                     ->update([
                                         "exceptionMsg" => empty($response) ? "未捕获的错误信息" : json_encode(
                                             array_merge($response, ["errorTitle" => $title]),
                                             JSON_UNESCAPED_UNICODE
                                         )
                                     ]);

            OpenShopSignOrderLogModel::logInsert(
                OpenShopSignOrderModel::query()->where("orderNo", self::$orderNo)->first()->id,
                OpenShopSignOrderLogModel::CONTRACT_EXCEPTION_HAPPEN,
                "系统",
                0,
                empty($response) ? "未捕获的错误信息" : $title . "-" . $response["message"]
            );
            NoticeService::contractError(self::$orderNo, $title);
        } catch (Exception $exception) {
            logException("契约锁异常信息回写失败", $exception, ["orderNo" => self::$orderNo], true, true);
        }


        throw new Exception(vsprintf("[ %s ] [ %s ]", [
            $title,
            is_array($response) ? collect($response)->toJson(JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : $response
        ]));
    }


    /**
     * 作废合同
     *
     * @param string $contractExtNo
     * @return array
     * @throws Exception
     */
    public static function invalidContract(string $contractExtNo): array
    {
        $userExtContractService = new self();
        $contractInvalidRequest = new ContractInvalidRequest();
        $contractInvalidRequest->setContractId($contractExtNo);
        $contractSignInvalidRequest = new ContractSignInvalidRequest();
        $invalidResponse            = $userExtContractService->sdkClient->service($contractInvalidRequest);

        //签署公章
        $userExtContractService->sdkClient = new SDKClient(
            config('qiyuesuo.tj_key'),
            config('qiyuesuo.tj_secret'),
            config('qiyuesuo.url'),
        );

        $contractSignInvalidRequest->setContractId($contractExtNo);
        $contractSignInvalidRequest->setSealId(config('qiyuesuo.tj_seal_id'));
        $invalidSignResponse = $userExtContractService->sdkClient->service($contractSignInvalidRequest);

        $response = compact("invalidResponse", "invalidSignResponse");

        if ($invalidResponse["code"] !== 0 || ($invalidSignResponse["code"] !== 0 && $invalidSignResponse["code"] != 1101)) {
            logInfo("作废合同 {$contractExtNo}", collect($response), true, true);
            throw new Exception("作废合同 {$contractExtNo} 失败");
        }
        return $response;
    }

    public static string $signUrl = "";

    /**
     * @param string $orderNo
     * @return string
     */
    public static function orderNotify(string $orderNo): string
    {
        try {
            self::$orderNo = $orderNo;
            $userContract  = OpenShopUserContractModel::query()
                                                      ->with("templateRel")
                                                      ->whereIn("contractType",
                                                          OpenShopUserContractModel::OPEN_SHOP_CONTRACT_GROUP)
                                                      ->where("orderNo", $orderNo)
                                                      ->orderBy("id", "desc")
                                                      ->first();

            $templateRelContractType = attributeGet($userContract, "templateRel.contractType", 0);
            self::generateUserContract($orderNo, $templateRelContractType ?? $userContract->contractType);
            self::saveCertificate($orderNo);
            return '';
        } catch (Exception $e) {
            logException("支付回调 合同异常", $e, ["orderNo" => $orderNo], true, true);
            return $e->getMessage();
        }
    }

    /**
     * @return mixed
     */
    public static function getRenewContractConfig()
    {
        return config('qiyuesuo.contract.renewContract.v8');
    }

    /**
     * 创建合同
     *
     * @param string $orderNo
     * @param int $contractType
     * @param string $fromDesc
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws ValidationException
     */
    public static function generateUserContract(string $orderNo, int $contractType = 0, string $fromDesc = "")
    {
        try {
            self::$orderNo = $orderNo;
            $orderDetail   = OpenShopSignOrderModel::orderDetail($orderNo, true, true, true, true)
                                                   ->getIterator()->current();

            $shopCode = (string)$orderDetail->kfShopCode;
            switch ($contractType) {
                case UserContractEnum::CONTRACT_TYPE_8://订单续签
                case UserContractEnum::CONTRACT_TYPE_9://新店加盟 - 分账模式 - 个体户 - v1
                    $categoryId = UserContractEnum::getContractTypeConfig($contractType)["categoryId"];
                    break;
                default://默认新签
                    //生成合同信息
                    $categoryId = self::getContactConfig(
                        $orderDetail->contractRel->version,
                        $orderDetail->contractRel->contractors,
                        $orderDetail->contractRel->mode,
                    )['categoryId'];
            }

            $bizId = vsprintf("%s-%s", [$orderDetail->orderNo, $orderDetail->contractRel->id]);

            $userExtContractService = new UserExtContractService();
            $contractResponse       = $userExtContractService
                ->generateContract()
                ->setContractMainBody(
                    $bizId,
                    config('qiyuesuo.contract_subject'),
                    "{$orderDetail->orderNo} - 合同描述",
                    true,
                    true
                )
                ->bindCategory($categoryId)
                ->setSignatory(self::orderBuildSignatory($orderDetail))
                ->templateRender(self::orderBuildTemplateParams($orderDetail, $shopCode))
                ->contractDraftRequest();


            $contract = self::handleResponse($contractResponse, "创建合同");
            $signUrl  = self::handleResponse($userExtContractService->getContractShortUrl($bizId), '获取签约链接地址');
            //合同信息数据库写入
            self::$signUrl = $signUrl["shorturl"];
            self::orderNotifySetContract($orderDetail, $contract, $signUrl["shorturl"]);

            //签署公章
            $userExtContractService->sdkClient = new SDKClient(
                config('qiyuesuo.tj_key'),
                config('qiyuesuo.tj_secret'),
                config('qiyuesuo.url'),
            );

            self::handleResponse(
                $userExtContractService->companySign($orderDetail->orderNo, $contract['id'],
                    config('qiyuesuo.tj_seal_id')),
                "签署公章"
            );
        } catch (Exception $exception) {
            handleException($exception, null, func_get_args(), "契约锁合同生成失败");
        }
    }


    public static function saveCertificate(string $orderNo)
    {
        $signOrder = OpenShopSignOrderModel::query()
                                           ->with(['baseInfoRel', 'contractRel'])
                                           ->where('orderNo', $orderNo)
                                           ->first();
        if (!$signOrder) {
            return;
        }

        if (null === $signOrder->baseInfoRel || null === $signOrder->contractRel) {
            return;
        }

        $identityCardModel = OpenShopUserIdentityCardModel::getDataByOrderNo($orderNo);
        if (null === $identityCardModel) {
            return;
        }
        $name = $identityCardModel->name;
//        $url  = QualificationImageService::shareImage($signOrder->shopCode, $name,
//                $identityCardModel->identityCardNumber, $signOrder->baseInfoRel->chooseShopAddressPrefix,
//                $signOrder->contractRel->startTime, $signOrder->contractRel->endTime)['path'] ?? '';

        if ($signOrder->contractRel->contractors == 1) {
            $url = QualificationImageService::shareImage($signOrder->shopCode, $name,
                $identityCardModel->identityCardNumber, $signOrder->baseInfoRel->chooseShopAddressPrefix,
                $signOrder->contractRel->startTime, $signOrder->contractRel->endTime)['path'] ?? '';
        } else {
            $url = QualificationImageService::shareCompanyImage($signOrder->shopCode,
                $signOrder->contractRel->companyName,
                $signOrder->contractRel->businessLicenseNumber, $signOrder->baseInfoRel->chooseShopAddressPrefix,
                $signOrder->contractRel->startTime, $signOrder->contractRel->endTime)['path'] ?? '';
        }


        //修改授权书
        OpenShopShopManual::query()
                          ->where('orderNo', $orderNo)
                          ->where('type', ShopManualEnum::TYPE_CERTIFICATE)
                          ->update([
                              'url'       => $url,
                              'updatedAt' => time(),
                          ]);
    }


    /**
     * @param OpenShopSignOrderModel $orderDetail
     * @param string $shopCode
     * @return array
     */
    public static function orderBuildTemplateParams(OpenShopSignOrderModel $orderDetail, string $shopCode): array
    {
        $isSelfWithAddress = $orderDetail->baseInfoRel->isSelfWithAddress;
        $shopProvince      = $shopCity = $shopDistrict = "-";
        if ($isSelfWithAddress == UserBaseInfoEnum::SELF_WITH_ADDRESS) {
            $shopAddressDetail = explode("-", $orderDetail->baseInfoRel->shopAddressPrefix);
            $shopProvince      = $shopAddressDetail[0] ?? "-";
            $shopCity          = $shopAddressDetail[1] ?? "-";
            $shopDistrict      = $shopAddressDetail[2] ?? "-";
        }

        $chooseShopAddressInfo = explode("-", $orderDetail->baseInfoRel->chooseShopAddressPrefix);

        $shopCount = $orderDetail->contractRel->shopCount;

        // 加盟费合计 = 品牌使用费 + 经营技术授予费 + 咨询指导服务费
        $jmfhj = $orderDetail->contractRel->initialFee +
            $orderDetail->contractRel->technologyTransferFee +
            $orderDetail->contractRel->guidanceFee;

        if ($orderDetail->contractRel->contractors == UserContractEnum::CONTRACT_PERSONAL) {
            // 签约人信息
            $signUserInfo = [
                // 加盟被特许人
                'jmsbtxr' => $orderDetail->identityCardRel->name,
                'jmsxm'   => $orderDetail->identityCardRel->name,
                'jmssfzh' => $orderDetail->identityCardRel->identityCardNumber,
                'jmszcdz' => vsprintf("%s%s", [
                    $orderDetail->baseInfoRel->addressPrefix,
                    $orderDetail->baseInfoRel->address
                ]),
            ];
        } else {
            // 签约公司信息
            $signUserInfo = [
                // 加盟签约公司信息
                'jmsbtxr' => $orderDetail->contractRel->companyName,
                'jmsxm'   => $orderDetail->contractRel->legalPerson,
                'jmssfzh' => $orderDetail->contractRel->businessLicenseNumber,
                'jmszcdz' => $orderDetail->contractRel->address
            ];
        }

        if ($shopProvince != '-') {
            $cnssheng = $shopProvince;
            $cnsshi   = $shopCity;
            $cnsqu    = $shopDistrict;
        } else {
            $cnssheng = $chooseShopAddressInfo[0] ?? "-";
            $cnsshi   = $chooseShopAddressInfo[1] ?? "-";
            $cnsqu    = '-';
        }


        return [
            //1.合同编号
            'dph'                        => sprintf("KF-%s", $shopCode),
            //2.签约人姓名
            'jsfwyf'                     => $orderDetail->identityCardRel->name,
            //3.签约人姓名
            'jsfwfzr'                    => $orderDetail->identityCardRel->name,
            //4.签约人身份证
            'jsfwsfzh'                   => $orderDetail->identityCardRel->identityCardNumber,
            //5.签约人地址
            'jsfwzcdz'                   => vsprintf("%s%s", [
                $orderDetail->baseInfoRel->addressPrefix,
                $orderDetail->baseInfoRel->address
            ]),
            //6.jszrf 技术服务费数字
            'jszrf'                      => formatPrice($orderDetail->contractRel->technologyTransferFee / $shopCount),
            //7.技术服务费rmb 大写
            'dx'                         => convertAmountToCn(formatPrice($orderDetail->contractRel->technologyTransferFee / $shopCount)),
            //8.代码写死-户名
            'skzhhm'                     => '厦门心有炸念餐饮管理有限公司',
            //9.skzhzh 代码写死-账号
            'skzhzh'                     => '110939648910401 ',
            //10.skzhkhh 代码写死-开户行
            'skzhkhh'                    => '招商银行股份有限公司北京太阳宫支行',
            //11.zprs 人数-写死 3 人
            'zprs'                       => 3,
            //12.qysj1 签约时间
            'qysj1'                      => formatDate(time()),

            // =================================================== No.2
            //1.dph 合同编号
            //2.jmsxm 加盟商姓名
            'jmsxm'                      => $signUserInfo['jmsxm'],
            //3.jmssfz 加盟商身份证
            'jmssfz'                     => $orderDetail->identityCardRel->identityCardNumber,
            //4.jmsdz 加盟商地址
            'jmsdz'                      => vsprintf("%s%s", [
                $orderDetail->baseInfoRel->addressPrefix,
                $orderDetail->baseInfoRel->address
            ]),
            //5.jmslxr 加盟商姓名
            'jmslxr'                     => $orderDetail->identityCardRel->name,
            //6.jmsdh 加盟商电话
            'jmsdh'                      => $orderDetail->baseInfoRel->mobile,
            //7.jmsltxdz 加盟商通讯地址
            'jmsltxdz'                   => vsprintf("%s%s", [
                $orderDetail->baseInfoRel->addressPrefix,
                $orderDetail->baseInfoRel->address
            ]),
            //8.jmsyx 加盟商邮箱
            'jmsyx'                      => $orderDetail->baseInfoRel->email,
            //9.qysj1 签约时间


            // =================================================== No.3
            //1.dph 合同编号
            //2.jmsbtxr
            'jmsbtxr'                    => $signUserInfo['jmsbtxr'],
            //3.jmsxm
            //4.jmssfzh
            'jmssfzh'                    => $signUserInfo['jmssfzh'],
            //5.jmszcdz
            'jmszcdz'                    => $signUserInfo['jmszcdz'],
            //6.htqx1
            'htqx1'                      => $orderDetail->contractRel->year,
            //7.htqxks1
            'htqxks1'                    => formatDateYmd($orderDetail->contractRel->startTime),
            //8.htqxks2
            'htqxks2'                    => formatDateYmd($orderDetail->contractRel->endTime),
            //9.jmsshen1
            'jmsshen1'                   => $chooseShopAddressInfo[0] ?? "-",
            'jmshi1'                     => $chooseShopAddressInfo[1] ?? "-",
            'jmsxian1'                   => $chooseShopAddressInfo[2] ?? "-",
            'jmsxiang'                   => $shopDistrict,
            'xzbhsf1'                    => $isSelfWithAddress == UserBaseInfoEnum::SELF_WITH_ADDRESS ? "√" : "",
            'jmsshen2'                   => $shopProvince,
            // 数字化运营系统初装费
            'szyyczf'                    => '8888',
            'jmshi2'                     => $shopCity,
            'jmsxian2'                   => $shopDistrict,
            'jmqu1'                      => empty($orderDetail->baseInfoRel->shopAddress) ? '-' : $orderDetail->baseInfoRel->shopAddress,
            'jmsdm1'                     => empty($orderDetail->baseInfoRel->shopName) ? '-' : $orderDetail->baseInfoRel->shopName,
            'xzbhsf2'                    => $isSelfWithAddress == UserBaseInfoEnum::SELF_WITH_ADDRESS ? "" : "√",
            'cnssheng'                   => $cnssheng,
            'cnsshi'                     => $cnsshi,
            'cnsqu'                      => $cnsqu,

            // 加盟费
            'jmf'                        => formatPrice($orderDetail->contractRel->initialFee / $shopCount),
            // 加盟费总计
            'jmfhj'                      => formatPrice($jmfhj / $shopCount),
            // 加盟费总计大写
            'jmfhjdx'                    => convertAmountToCn(formatPrice($jmfhj / $shopCount)),
            // 品牌使用费
            'ppsyf'                      => formatPrice($orderDetail->contractRel->initialFee / $shopCount),
            // 经营技术授予费
            'jyjssyf'                    => formatPrice($orderDetail->contractRel->technologyTransferFee / $shopCount),
            // 咨询指导服务费
            'zxzdfwf'                    => formatPrice($orderDetail->contractRel->guidanceFee / $shopCount),
            // 账户名称
            'yfzhmc'                     => $orderDetail->baseInfoRel->cardAccountName,
            // 开户行
            'yfkhh'                      => $orderDetail->baseInfoRel->cardBankName,
            // 银行账号
            'yfyhzh'                     => $orderDetail->baseInfoRel->cardNo,
            // 加盟费大写
            'jmfdx'                      => convertAmountToCn(formatPrice($orderDetail->contractRel->initialFee / $shopCount)),
            // 特许权使用费
            'txqsyf'                     => formatPrice($orderDetail->contractRel->managementCostEveryYear / $shopCount),
            // 特许权使用费 大写
            'txqsyfdx'                   => convertAmountToCn(formatPrice($orderDetail->contractRel->managementCostEveryYear / $shopCount)),
            // 履约保证金
            'lybzj'                      => formatPrice($orderDetail->contractRel->deposit / $shopCount),
            // 履约保证金 大写
            'lybzjdx'                    => convertAmountToCn(formatPrice($orderDetail->contractRel->deposit / $shopCount)),
            // 装修保证金
            'decorationDeposit'          => formatPrice($orderDetail->contractRel->decorationDeposit / $shopCount),
            // 装修保证金 大写
            'decorationDepositUppercase' => convertAmountToCn(formatPrice($orderDetail->contractRel->decorationDeposit / $shopCount)),

            'jftxlxr'   => '王植巍',
            'jftxlxrdh' => '13146129090',
            'jftxlxrdz' => '北京市朝阳区酒仙桥北路甲10号院C门603号',
            'jftxlxryx' => 'kuafutxjy@51kuafu.com',
            'yftxlxr'   => $orderDetail->identityCardRel->name,

            'yftxlxrdh'   => $orderDetail->baseInfoRel->mobile,
            'yftxlxrtxdz' => vsprintf("%s%s", [
                $orderDetail->baseInfoRel->addressPrefix,
                $orderDetail->baseInfoRel->address
            ]),
            'yftxlxryx'   => $orderDetail->baseInfoRel->email,
            'yftxlxrwx'   => $orderDetail->baseInfoRel->weChatNumber,
            'qyxm'        => $orderDetail->identityCardRel->name,
            /**********   续签 ************/
            'jfqysj'      => (function () use ($orderDetail) {
                $signTime = attributeGet($orderDetail, "lastFinishContractRel.signTime", null);
                return $signTime > 0 ? formatDateYmd($signTime) : "-";
            })(),
            'jmdzshen'    => $cnssheng,
            'jmdzshi'     => $cnsshi,
            'jmdzqu'      => $cnsqu,
            'qyshijian'   => formatDateYmd(time()),
            /**********   续签 ************/
        ];
    }

    /**
     * @param OpenShopSignOrderModel $orderDetail
     * @return object[]
     */
    public static function orderBuildSignatory(OpenShopSignOrderModel $orderDetail): array
    {

        $signatory = [
            [
                "tenantType" => "COMPANY",
                "tenantName" => config('qiyuesuo.wps_company_name'),
                "serialNo"   => 1
            ],
            [
                "tenantType" => "COMPANY",
                "tenantName" => config('qiyuesuo.tj_company_name'),
                "serialNo"   => 2,
                "receiver"   => [
                    "contact"     => config('qiyuesuo.contract_receiver_mobile'),
                    "contactType" => "MOBILE"
                ]
            ]
        ];

        if ($orderDetail->contractRel->contractors == UserContractEnum::CONTRACT_PERSONAL) {
            // 签约人信息
            $signatory = array_merge($signatory, [
                [
                    "tenantType"   => "PERSONAL",
                    "tenantName"   => $orderDetail->identityCardRel->name,
                    "serialNo"     => 3,
                    "userAuthInfo" => [
                        "idCardNo" => $orderDetail->identityCardRel->identityCardNumber
                    ],
                    "receiver"     => [
                        "contact"     => $orderDetail->baseInfoRel->mobile,
                        "contactType" => "MOBILE"
                    ]
                ]
            ]);
        } else {
            // 签约公司信息
            $signatory = array_merge($signatory, [
                [
                    "tenantType" => "COMPANY",
                    "tenantName" => $orderDetail->contractRel->companyName,
                    "serialNo"   => 3,
//                "userAuthInfo" => (object)[
//                    "idCardNo" => $orderDetail->identityCardRel->identityCardNumber
//                ],
                    "receiver"   => [
                        "contact"     => $orderDetail->baseInfoRel->mobile,
                        "contactType" => "MOBILE"
                    ]
                ]
            ]);

        }

        return json_decode(json_encode($signatory));
    }


    /**
     * @param OpenShopSignOrderModel $orderDetail
     * @param $contract
     * @param string $signUrl
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function orderNotifySetContract(OpenShopSignOrderModel $orderDetail, $contract, string $signUrl)
    {
        try {
            DB::beginTransaction();

            $userExtContractService = new self();
            $fileSystem             = app()->get('files');
            $dir                    = getTmpDir("contract/" . formatDateYmd(time()));
            if (!$fileSystem->isDirectory($dir)) {
                $fileSystem->makeDirectory($dir, 0777, true);
            }

            OpenShopUserExtContractModel::query()->insert(collect($contract["documents"])->map(function (
                $v
            ) use ($orderDetail, $signUrl, $dir, $fileSystem, $userExtContractService) {

                $documentDownloadRequest = new DocumentDownloadRequest($v['id']);
                $filePath                = $dir . "/" . $v["id"] . ".pdf";
                self::handleResponse(
                    $userExtContractService->sdkClient->downloadService($documentDownloadRequest,
                        $filePath),
                    "契约锁合同转oss - 下载文件失败： 【 {$v["id"]} 】"
                );
                $ossInfo = PrivateFileUtil::uploadFile(
                    $filePath,
                    'pdf',
                    generateFileKey() . ".pdf"
                );
                $fileSystem->delete($filePath);

                return [
                    'contractId'    => $orderDetail->contractRel->id,
                    'contractUrl'   => $signUrl,
                    'contractExtNo' => $v['id'],
                    'previewUrl'    => $ossInfo["path"],
                    'contractName'  => "No." . $orderDetail->shopCode . "-" . $v['title'],
                    'createdAt'     => time(),
                    'updatedAt'     => time()
                ];
            })->values()->toArray());

            OpenShopUserContractModel::query()->where('id', $orderDetail->contractRel->id)->update([
                'contractExtNo' => $contract['id'],
                "categoryId"    => $contract["category"]["id"] ?? 0,
                "categoryName"  => $contract["category"]["name"] ?? "",
                'updatedAt'     => time()
            ]);
            DB::commit();
        } catch (Exception $e) {
            DB::rollBack();
            logException("支付回调 - 合同数据库写入失败", $e, ["orderNo" => $orderDetail->orderNo], true, true);
        }
    }

    /**
     * 契约锁合同转oss
     *
     * @param string $contractExtNo 第三方主合同编号
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function transSave(string $contractExtNo): void
    {
        try {
            $userContract = OpenShopUserContractModel::query()->where("contractExtNo", $contractExtNo)->first();
            if ($userContract) {
                self::$orderNo          = $userContract->orderNo;
                $userExtContractService = new self();
                $fileSystem             = app()->get('files');
                $dir                    = getTmpDir("/contract/" . formatDateYmd(time()));
                if (!$fileSystem->isDirectory($dir)) {
                    $fileSystem->makeDirectory($dir, 0777, true);
                }
                OpenShopUserExtContractModel::query()->where("contractId", $userContract->id)->get()->each(function (
                    OpenShopUserExtContractModel $openShopUserExtContract
                ) use ($userExtContractService, $dir, $fileSystem) {
                    $documentDownloadRequest = new DocumentDownloadRequest($openShopUserExtContract->contractExtNo);
                    $filePath                = $dir . "/" . $openShopUserExtContract->contractExtNo . ".pdf";
                    self::handleResponse(
                        $userExtContractService->sdkClient->downloadService($documentDownloadRequest,
                            $filePath),
                        "契约锁合同转oss - 下载文件失败： 【 {$openShopUserExtContract->contractExtNo} 】"
                    );
                    $ossInfo = PrivateFileUtil::uploadFile(
                        $filePath,
                        'pdf',
                        generateFileKey() . ".pdf"
                    );
//                    $ossInfo = OssService::uploadFile($filePath, "pdf");
                    $fileSystem->delete($filePath);
                    $openShopUserExtContract->downloadUrl = $ossInfo['path'];
                    $openShopUserExtContract->updatedAt   = time();
                    $openShopUserExtContract->save();
                });
            }
        } catch (Exception $exception) {
            logException("合同转oss异常", $exception, ["document" => $contractExtNo], true, true);
        }
    }


    /**
     * 获取合同详情
     *
     * @param string $extContractId
     * @return mixed|string|null
     */
    public static function getContractDetailByExtContractId(string $extContractId)
    {
        $userExtContractService = new self();
        $contractDetailRequest  = new ContractDetailRequest();
        $contractDetailRequest->setContractId($extContractId);
        return $userExtContractService->sdkClient->service($contractDetailRequest);
    }

    /**
     * 合同催签
     *
     * @param string $extContractId
     * @return mixed|string|null
     */
    public static function contractNotice(string $extContractId)
    {
        $userExtContractService = new self();
        $contractNoticeRequest  = new ContractNoticeRequest();
        $contractNoticeRequest->setContractId($extContractId);
        return $userExtContractService->sdkClient->service($contractNoticeRequest);
    }

    /**
     * 下载重试
     *
     * @param $userExtContractService
     * @param $openShopUserExtContract
     * @param $documentDownloadRequest
     * @param $filePath
     * @param int $times
     * @throws Exception
     */
    public function downloadContract(
        $userExtContractService,
        $openShopUserExtContract,
        $documentDownloadRequest,
        $filePath,
        int $times = 0
    ) {
        try {
            self::handleResponse(
                $userExtContractService->sdkClient->downloadService($documentDownloadRequest,
                    $filePath),
                "契约锁合同转oss - 下载文件失败： 【 {$openShopUserExtContract->contractExtNo} 】"
            );
        } catch (Exception $exception) {
            if ($times <= 3) {
                $times++;
                $this->downloadContract(
                    $userExtContractService,
                    $openShopUserExtContract,
                    $documentDownloadRequest,
                    $filePath,
                    $times
                );
            } else {
                throw $exception;
            }
        }
    }

    /**
     * 获取契约锁回调信息
     * @param $data
     * @param int $contactVersion
     * @param int $contractors
     * @param int $mode
     * @return void
     * @throws ContainerExceptionInterface
     * @throws GuzzleException
     * @throws NotFoundExceptionInterface
     */
    public static function ContractSigningNotify(
        $data,
        int $contactVersion = 1,
        $contractors = UserContractEnum::CONTRACT_PERSONAL,
        $mode = OpenShopContractTemplateModel::MODE_1
    ) {
        $secret         = self::getContactConfig($contactVersion, $contractors, $mode)['notifySecret'];
        $checkSignature = md5($data['timestamp'] . $secret);
        if ($checkSignature != $data['signature']) {
            //验证签名失败是否需要发飞书告警
            $signatureData = [
                'checkSignature' => $checkSignature,
                'signature'      => $data['signature']
            ];
            logException("签约回调-验证失败", null, $signatureData, false, true);
            //扔出异常 继续回调
            throw new CustomHttpResponseException(ErrCode::CODE_NOTIFY_ERROR, null, '', [], true, true,
                Response::HTTP_INTERNAL_SERVER_ERROR);
        } else {
            $original = $data;
            $encrypt  = $data['content'];
            $deData   = CryptUtils::aesDerypt($encrypt, $secret);
            Log::info('签约合同回调信息-解密:' . $deData);
            $data              = json_decode($deData, true);
            $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($data["contractId"]);
            if (!$userContractModel) {
                Log::info(json_encode(
                    array_merge(
                        ["originalData" => $original],
                        ["decodeData" => $data],
                        ["title" => "获取合同信息失败"]
                    ),
                    JSON_UNESCAPED_UNICODE
                ));
                exit(1);
            }

            //更新合同主表状态
            $userContractModel->detailStatus = $data["contractStatus"];
            $userContractModel->save();

            switch ($data["callbackType"]) {
                case ContractStatusEnum::CALL_BACK_TYPE_COMPLETE:
                    //合同签约完成
                    if ($data['contractStatus'] == ContractStatusEnum::COMPLETE) {
                        Log::info('签约合同回调信息-进入回调处理:' . json_encode($data, JSON_UNESCAPED_UNICODE));
                        if (isset($data['bizId'])) {
                            $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($data["contractId"]);
                            $signOrder         = $userContractModel->signOrderRel;

                            //更新合同主表状态
                            $userContractModel->detailStatus = ContractStatusEnum::COMPLETE;
                            $userContractModel->signTime     = time();
                            $userContractModel->save();

                            //订单合同状态是否正常 变更中合同置为正常
//                            if ($signOrder->contractStatus != OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL) {
//                                //更新合同状态为正常
//                                OpenShopSignOrderModel::query()
//                                                      ->where("orderNo", $signOrder->orderNo)
//                                                      ->update([
//                                                          "contractStatus" => OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL
//                                                      ]);
//                            }

                            if ($signOrder->step < SignOrderEnum::STEP_5) {
                                self::updateExtContractStatusAndGenerateShop(
                                    $signOrder->orderNo,
                                    ContractStatusEnum::CODE_NUM[$data['contractStatus']],
                                    $data['contractId']
                                );

                            } else {
                                //转存合同
                                UserExtContractService::transSave($data['contractId']);
                                //获取主订单id
                                $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($data['contractId']);
                                //根据contractId 修改状态
                                OpenShopUserExtContractModel::updateByContractId(
                                    $userContractModel->id,
                                    ContractStatusEnum::CODE_NUM[$data['contractStatus']]
                                );

                                $invalidContract = OpenShopUserContractModel::query()
                                                                            ->where("orderNo", $signOrder->orderNo)
                                                                            ->where("detailStatus",
                                                                                ContractStatusEnum::COMPLETE)
                                                                            ->where("contractStatus",
                                                                                OpenShopUserContractModel::CONTRACT_STATUS_INVALID)
                                                                            ->orderBy("id", "desc")
                                                                            ->first();

                                if ($invalidContract && $invalidContract->contractExtNo) {
                                    try {
                                        UserExtContractService::invalidContract($invalidContract->contractExtNo);
                                    } catch (Exception $exception) {

                                    }
                                }

                                //修改远程门店手机号
                                $contact = $signOrder->identityCardRel->name;
                                RmsShopRemote::updateShopMobile($signOrder->shopCode, $signOrder->baseInfoRel->mobile,
                                    $contact);
                            }
                            //签约阶段-在「商家开店合同签署」完成之后，进行推送 评价消息
                            $rmsShop = (new RmsShopApi())->getShopByCode($signOrder->shopCode);
                            if ($rmsShop['code']) {
                                $shopId = $rmsShop['data']['id'];
                                NotifyService::notify($signOrder->orderNo, AppraiseModel::TYPE_OPENSHOP_SIGN, 0,
                                    $shopId);
                            }
                        }
                    }
                    break;
                case ContractStatusEnum::CALL_BACK_TYPE_INVALIDING:
                    switch ($data["contractStatus"]) {
                        case ContractStatusEnum::INVALIDED:
                            $invalidatedClosure = function () use ($userContractModel) {
                                $userContractModel->isDeleted = 1;
                                $userContractModel->save();

                                //契约锁合同更新签约信息
                                OpenShopUserExtContractModel::query()->where("contractId", $userContractModel->id)
                                                            ->update([
                                                                "signStatus" => 1,
                                                                "signTime"   => time()
                                                            ]);

                                //更新合同状态为正常
                                $signOrder = $userContractModel->signOrderRel;
                                if ($signOrder && $signOrder->contractStatus != OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL) {
                                    //更新合同状态为正常
                                    OpenShopSignOrderModel::query()
                                                          ->where("orderNo", $signOrder->orderNo)
                                                          ->update([
                                                              "contractStatus" => OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL
                                                          ]);
                                }
                            };
                            $invalidatedClosure();
                            break;
                    }
                    break;
            }
        }
    }

    /**
     * 修改用户合同状态
     * @param $contractId
     * @param $status
     */
    public static function updateExtContractStatusAndGenerateShop($bizId, $status, $contractId)
    {
        //获取加盟商基本信息
        $collection = OpenShopSignOrderModel::orderDetail($bizId, true, false, true, false, false, true, false)
                                            ->getIterator()->current();
        //获取主订单id
        $id = OpenShopUserContractModel::getUserIdByOrderNo($bizId);
        DB::beginTransaction();
        try {
            //根据contractId 修改状态
            OpenShopUserExtContractModel::updateByContractId($id, $status);
            //修改签约订单表状态
            OpenShopSignOrderModel::updateStepByOrderNo($bizId, SignOrderEnum::STEP_5);
            //todo 潘 签约成功之后发送订单处理事件
            $order = OpenShopSignOrderModel::find($collection['id']);

            //写进合同链接
            self::transSave($contractId);
            //主流程步骤变更
            OpenShopMainProcessModel::query()->where("orderNo", $bizId)
                                    ->update([
                                        "step"      => MainProcessEnum::MAIN_PROCESS_SHOP_LOCATION,
                                        "updatedAt" => time()
                                    ]);

            //选址信息插入
            OpenShopLocationModel::query()->insert([
                'orderNo'       => $bizId,
                'mainProcessId' => $collection->progressRel->id,
                'createdAt'     => time(),
                'updatedAt'     => time()
            ]);

            // 更新主表的当前nowStepStatus
            OpenShopMainProcessModel::updateNowStepStatus($bizId, MissionTemplateEnum::STEP_STATUS_3);

            DB::commit();

            // 创建任务
            SiteMissionService::genMission($order->orderNo, MissionTemplateEnum::STEP_STATUS_3);

            event(new OrderSignedEvent($order));
            //签约成功之后流程事件
            event(new OpenShopProcessEvent(
                0,
                $collection['mainProcessId'],
                MainProcessEnum::MAIN_PROCESS_INVESTMENT_SIGN,
                MainProcessEnum::INVESTMENT_SIGN_CONTRACT_SIGNED
            ));

            // 任务后的事件
            OrderService::updateOrderPermissionAnchor($order->orderNo);

        } catch (Exception $exception) {
            DB::rollBack();
            Log::warning($exception);
            //签约合同成功之后 回调处理数据库状态异常
            $notifyData = [
                'id'     => $id,
                'bizId'  => $bizId,
                'status' => $status
            ];
            logException("签约成功-修改数据库状态失败", $exception, $notifyData, true, true);
            //扔出异常 继续回调
            throw new CustomHttpResponseException(ErrCode::CODE_NOTIFY_ERROR, null, '', [], true, true,
                Response::HTTP_INTERNAL_SERVER_ERROR);
        }

    }

    /**
     * @param string $bizId
     * @param string $contractSubject
     * @param string $contractDescription
     * @param string $contractType
     * @param Closure|array $buildSignatory
     * @param Closure|array $buildTemplateParams
     * @param $orderNo
     * @return array
     * @throws Exception
     */
    public static function commonGenerateContract(
        string $bizId,
        string $contractSubject,
        string $contractDescription,
        string $contractType,
        $buildSignatory = [],
        $buildTemplateParams = [],
        $orderNo
    ): array {
        try {
            if (!self::$orderNo && $orderNo) {
                self::$orderNo = $orderNo;
            }
            $categoryId = config("qiyuesuo.{$contractType}")["categoryId"];

            $userExtContractService = new self();
            $contractResponse       = $userExtContractService
                ->generateContract()
                ->setContractMainBody(
                    $bizId,
                    $contractSubject,
                    $contractDescription,
                    true,
                    true
                )
                ->bindCategory($categoryId)
                ->setSignatory($buildSignatory)
                ->templateRender($buildTemplateParams)
                ->contractDraftRequest();

            $contract = self::handleResponse($contractResponse, "{$contractSubject} - {$bizId}");
            $sign     = self::handleResponse($userExtContractService->getContractShortUrl($bizId), '获取签约链接地址');

            return [
                "contractResponse" => $contract,
                "signUrl"          => $sign["shorturl"]
            ];
        } catch (Exception $e) {
            logException("{$contractSubject} - {$bizId}", $e, ["bizId" => $bizId], true, true);
            throw new Exception("生成合同失败 - {$e->getMessage()}");
        }
    }


    /**
     * 合同模版渲染
     *
     * @param string $contractType
     * @param OpenShopSignOrderModel $signOrderModel
     * @param array $extraParams
     * @return string[]|void
     */
    public static function commonBuildTemplateParams(
        string $contractType,
        OpenShopSignOrderModel $signOrderModel,
        array $extraParams
    ) {
        $jflxdz         = "北京市密云区经济开发区兴盛南路8号开发区办公楼501室-室-2631(经济开发区集中办公区)";
        $limitCloseDays = 7;
        $limitBackFiles = 7;
        $limitBackFee   = 7;
        $feeType_1      = "-";
        $feeType_2      = "-";
        $feeTypeVal_1   = "-";
        $feeTypeVal_2   = "-";

        if ($signOrderModel->contractRel->contractors == UserContractEnum::CONTRACT_PERSONAL) {
            $contractUsername = $signOrderModel->identityCardRel->name;
            $contractNo       = $signOrderModel->identityCardRel->identityCardNumber;
            $contractAddress  = vsprintf(
                "%s-%s",
                [
                    $signOrderModel->baseInfoRel->addressPrefix,
                    $signOrderModel->baseInfoRel->address
                ]
            );
        } else {
            $contractUsername = $signOrderModel->contractRel->companyName ?? "";
            $contractNo       = $signOrderModel->contractRel->businessLicenseNumber ?? "";
            $contractAddress  = $signOrderModel->contractRel->address ?? "";
        }

        switch ($contractType) {
            case UserContractEnum::CONTRACT_TYPE_3_KEY:
                return array_merge([
                    "jflxdz"   => $jflxdz,//联系地址
                    "yfxm"     => $contractUsername,//乙方
                    "yfsfzh"   => $contractNo,
                    "yflxdz"   => $contractAddress,
                    "yflxfs"   => $signOrderModel->baseInfoRel->mobile,
                    "qysj"     => formatDate(
                        (
                            $signOrderModel->normalContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty()
                        ) ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                  ->current()->signTime : 0,
                    ),
                    "htbh"     => "KF-" . ($signOrderModel->shopCode ?? "-"),
                    "yfsqdz"   => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "jcsj"     => formatDateYmd(time()),
                    "jiri1"    => $limitCloseDays,
                    "jiri2"    => $limitBackFiles,
                    "jiri3"    => $limitBackFee,
                    "tqfy1"    => $feeType_1,
                    "tqfy2"    => $feeTypeVal_1,
                    "tqfy3"    => $feeType_2,
                    "tqfy4"    => $feeTypeVal_2,
                    "ycxfy1"   => "-",
                    "ppsyf"    => "-",
                    "jssqf"    => "-",
                    "lybzhj"   => "-",
                    "txqsyf1"  => "-",
                    "yunfuwu1" => "-",
                    "yfzhmc"   => $signOrderModel->baseInfoRel->cardAccountName,
                    "yfkhh"    => $signOrderModel->baseInfoRel->cardBankName,
                    "yfzh"     => $signOrderModel->baseInfoRel->cardNo,
                    "yftxqsyf" => "12000"
                ], $extraParams);
                break;
            case UserContractEnum::CONTRACT_TYPE_6_KEY:
                return array_merge([
                    "xyzn"     => "厦门心有炸念餐饮管理有限公司",
                    "jflxdz"   => $jflxdz,//联系地址
                    "yfxm"     => $contractUsername,//乙方
                    "yfsfzh"   => $contractNo,
                    "yflxdz"   => $contractAddress,
                    "yflxfs"   => $signOrderModel->baseInfoRel->mobile,
                    "qysj"     => formatDate(
                        (
                            $signOrderModel->normalContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty()
                        ) ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                  ->current()->signTime : 0,
                    ),
                    "htbh"     => "KF-" . ($signOrderModel->shopCode ?? "-"),
                    "yfsqdz"   => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "jcsj"     => formatDateYmd(time()),
                    "jiri1"    => $limitCloseDays,
                    "jiri2"    => $limitBackFiles,
                    "jiri3"    => $limitBackFee,
                    "tqfy1"    => $feeType_1,
                    "tqfy2"    => $feeTypeVal_1,
                    "tqfy3"    => $feeType_2,
                    "tqfy4"    => $feeTypeVal_2,
                    "ycxfy1"   => "-",
                    "ppsyf"    => "-",
                    "jssqf"    => "-",
                    "txqsyf1"  => "-",
                    "yunfuwu1" => "-",
                    "yfzhmc"   => $signOrderModel->baseInfoRel->cardAccountName,
                    "yfkhh"    => $signOrderModel->baseInfoRel->cardBankName,
                    "yfzh"     => $signOrderModel->baseInfoRel->cardNo,
                    "yftxqsyf" => "12000"
                ], $extraParams, [
                    "lybzj" => attributeGet($extraParams, "lybzhj", "-"),
//                    "ycxfy1" => attributeGet($extraParams, "ycxfy1", "-"),
//                    "txqsyf1" => attributeGet($extraParams, "txqsyf1", "-"),
                ]);
                break;
            case UserContractEnum::CONTRACT_TYPE_4_KEY:
                return array_merge([
                    "jflxdz"   => $jflxdz,//联系地址
                    "yfxm"     => $contractUsername,//乙方
                    "yfsfzh"   => $contractNo,
                    "yflxdz"   => $contractAddress,
                    "yflxfs"   => $signOrderModel->baseInfoRel->mobile,
                    "qysj"     => formatDate(
                        (
                            $signOrderModel->normalContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty()
                        ) ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                  ->current()->signTime : 0
                    ),
                    "htbh"     => "KF-" . ($signOrderModel->shopCode ?? "-"),
                    "yfsqdz"   => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "jcsj"     => formatDateYmd(time()),
                    "jiri1"    => $limitCloseDays,
                    "jiri2"    => $limitBackFiles,
                    "jiri3"    => $limitBackFee,
                    "tqfy1"    => $feeType_1,
                    "tqfy2"    => $feeTypeVal_1,
                    "tqfy3"    => $feeType_2,
                    "tqfy4"    => $feeTypeVal_2,
                    "ycxfy1"   => "-",
                    "ppsyf"    => "-",
                    "jssqf"    => "-",
                    "zxzfd1"   => "-",
                    "txqsyf1"  => "-",
                    "yunfuwu1" => "-",
                    "lybzj"    => "-",
                    "yfzhmc"   => $signOrderModel->baseInfoRel->cardAccountName,
                    "yfkhh"    => $signOrderModel->baseInfoRel->cardBankName,
                    "yfzh"     => $signOrderModel->baseInfoRel->cardNo,
                    "yftxqsyf" => "12000"
                ], $extraParams);
                break;
            case UserContractEnum::CONTRACT_TYPE_5_KEY:
                return array_merge([
                    "lxdz"     => $jflxdz,
                    "yfxm"     => $contractUsername,
                    "yfsfzh"   => $contractNo,
                    "yflxdz"   => $contractAddress,
                    "yflxfs"   => $signOrderModel->baseInfoRel->mobile,
                    "qdrq"     => formatDate(
                        $signOrderModel->normalContractRel && $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty() ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                                                                                                                           ->current()->signTime : 0
                    ),
                    "htbh"     => $signOrderModel->shopCode ?? "-",
                    "sqdz"     => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "qcrq"     => formatDateYmd(time()),
                    "jmf"      => "-",
                    "ppsfy"    => "-",
                    "jsjyf"    => "-",
                    "zxzdf"    => "-",
                    "txqsyf"   => "-",
                    "szhfy"    => "-",
                    "lybzj"    => "-",
                    "yfzhmc"   => $signOrderModel->baseInfoRel->cardAccountName,
                    "yfkhh"    => $signOrderModel->baseInfoRel->cardBankName,
                    "yfzh"     => $signOrderModel->baseInfoRel->cardNo,
                    "yftxqsyf" => "12000"
                ], $extraParams);
            case UserContractEnum::CONTRACT_TYPE_7_KEY:
                return array_merge([
                    "xyzn"     => "厦门心有炸念餐饮管理有限公司",
                    "jflxdz"   => $jflxdz,//联系地址
                    "yfsqdz"   => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "jcsj"     => formatDateYmd(time()),
                    "zxzfd1"   => attributeGet($signOrderModel, "contractRel.guidanceFee", "-"),
                    "jiri3"    => $limitBackFee,
                    "lxdz"     => $jflxdz,
                    "yfxm"     => $contractUsername,
                    "yfsfzh"   => $contractNo,
                    "yflxdz"   => $contractAddress,
                    "yflxfs"   => $signOrderModel->baseInfoRel->mobile,
                    "qdrq"     => formatDate(
                        $signOrderModel->normalContractRel && $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty() ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                                                                                                                           ->current()->signTime : 0
                    ),
                    "htbh"     => $signOrderModel->shopCode ?? "-",
                    "sqdz"     => $signOrderModel->baseInfoRel->chooseShopAddressPrefix,
                    "qcrq"     => formatDateYmd(time()),
                    "jmf"      => "-",
                    "ppsfy"    => "-",
                    "jsjyf"    => "-",
                    "zxzdf"    => "-",
                    "txqsyf"   => "-",
                    "szhfy"    => "-",
                    "lybzj"    => "-",
                    "yfzhmc"   => $signOrderModel->baseInfoRel->cardAccountName,
                    "yfkhh"    => $signOrderModel->baseInfoRel->cardBankName,
                    "yfzh"     => $signOrderModel->baseInfoRel->cardNo,
                    "yftxqsyf" => "12000",
                    "qysj"     => formatDate(
                        (
                            $signOrderModel->normalContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel &&
                            $signOrderModel->normalContractRel->userExtContractRel->isNotEmpty()
                        ) ? $signOrderModel->normalContractRel->userExtContractRel->getIterator()
                                                                                  ->current()->signTime : 0,
                    ),
                    "tqfy1"    => $feeType_1,
                    "tqfy2"    => $feeTypeVal_1,
                    "tqfy3"    => $feeType_2,
                    "tqfy4"    => $feeTypeVal_2,
                ], $extraParams, [
                    "ycxfy1"   => attributeGet($extraParams, "jmf", 0),
                    "ppsyf"    => attributeGet($extraParams, "ppsfy", 0),
                    "jssqf"    => attributeGet($extraParams, "jsjyf", 0),
                    "txqsyf1"  => attributeGet($extraParams, "txqsyf", 0),
                    "yunfuwu1" => attributeGet($extraParams, "szhfy", 0),
                    "zxzfd1"   => attributeGet($extraParams, "zxzdf", 0),
                ]);
            case UserContractEnum::CONTRACT_TYPE_8_KEY:
                return self::orderBuildTemplateParams($signOrderModel, $signOrderModel->shopCode ?? "-");
                break;
        }
    }

    /**
     * 合约签署方定义
     *
     * @param string $contractType
     * @param OpenShopSignOrderModel $signOrderModel
     * @param array $extraParams
     * @return mixed|void
     * @throws Exception
     */
    public static function commonBuildBuildSignatory(
        string $contractType,
        OpenShopSignOrderModel $signOrderModel,
        array $extraParams = []
    ) {
        switch ($contractType) {
            case UserContractEnum::CONTRACT_TYPE_3_KEY:
            case UserContractEnum::CONTRACT_TYPE_4_KEY:
            case UserContractEnum::CONTRACT_TYPE_5_KEY:
            case UserContractEnum::CONTRACT_TYPE_6_KEY:
            case UserContractEnum::CONTRACT_TYPE_7_KEY:
            case UserContractEnum::CONTRACT_TYPE_8_KEY:
                $signatory = [
                    [
                        "tenantType" => "COMPANY",
                        "tenantName" => config('qiyuesuo.wps_company_name'),
                        "serialNo"   => 1
                    ],
                    [
                        "tenantType"   => "PERSONAL",
                        "tenantName"   => $extraParams["yfxm"] ?? $signOrderModel->identityCardRel->name,
                        "serialNo"     => 2,
                        "userAuthInfo" => [
                            "idCardNo" => $extraParams["yfsfzh"] ?? $signOrderModel->identityCardRel->identityCardNumber
                        ],
                        "receiver"     => [
                            "contact"     => $extraParams["yflxfs"] ?? $signOrderModel->baseInfoRel->mobile,
                            "contactType" => "MOBILE"
                        ]
                    ]
                ];
                return json_decode(json_encode($signatory));
                break;
            default:
                throw new Exception("未定义的合同类型");
                break;
        }
    }

    /**
     * 获取契约锁回调信息
     * @param $data
     * @return void
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface|GuzzleException|ValidationException
     */
    public static function commonSignNotify($data)
    {
        try {
            $contractType   = $data["type"] ?? 0;
            $secret         = UserContractEnum::getContractTypeConfig($contractType)["notifySecret"];
            $checkSignature = md5($data['timestamp'] . $secret);

            if ($checkSignature != $data['signature']) {
                throw new Exception(json_encode(array_merge($data, ["title" => "契约锁签名校验失败"]),
                    JSON_UNESCAPED_UNICODE));
            } else {
                if (!($decodeContent = CryptUtils::aesDerypt($data['content'], $secret))) {
                    throw new Exception(json_encode(array_merge($data, ["title" => "契约锁解密失败"]),
                        JSON_UNESCAPED_UNICODE));
                }
                $decodeData = json_decode($decodeContent, true);
                Log::info(json_encode(
                    array_merge(
                        ["originalData" => $data],
                        ["decodeData" => $decodeData],
                        ["title" => "回调解密数据写入"]
                    ),
                    JSON_UNESCAPED_UNICODE
                ));

                $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($decodeData["contractId"]);
                if (!$userContractModel) {
                    Log::info(json_encode(
                        array_merge(
                            ["originalData" => $data],
                            ["decodeData" => $decodeData],
                            ["title" => "获取合同信息失败"]
                        ),
                        JSON_UNESCAPED_UNICODE
                    ));
                    exit(1);
                }

                $templateContractType = attributeGet(
                    $userContractModel,
                    "templateRel.contractType",
                    0
                );

                if ($userContractModel->contractType != $contractType && $templateContractType != $contractType) {
                    throw new Exception(
                        json_encode(array_merge(["decodeData" => $decodeData], ["requestParams" => $data],
                            ["title" => "合同类型验证失败"]), JSON_UNESCAPED_UNICODE)
                    );
                }

                //更新合同主表状态
                $userContractModel->detailStatus = $decodeData["contractStatus"];
                $userContractModel->save();

                switch ($contractType) {
                    case UserContractEnum::CONTRACT_TYPE_3:
                    case UserContractEnum::CONTRACT_TYPE_4:
                    case UserContractEnum::CONTRACT_TYPE_5:
                    case UserContractEnum::CONTRACT_TYPE_6:
                    case UserContractEnum::CONTRACT_TYPE_7://解约
                        self::cancelShopContractNotify($decodeData, $userContractModel);
                        break;
                    case UserContractEnum::CONTRACT_TYPE_8://续签
                        self::renewShopContractNotify($decodeData, $userContractModel);
                        break;
                    case UserContractEnum::CONTRACT_TYPE_9://新店加盟
                        self::newShopContractNotify($decodeData, $userContractModel);
                        break;
                    default:
                        throw new Exception("合同类型不存在");
                }
            }
        } catch (Exception $exception) {
            handleException($exception);
        }
    }

    /**
     * 续签合同回调处理方法
     *
     * @param array $decodeData
     * @param OpenShopUserContractModel $userContractModel
     * @throws ContainerExceptionInterface
     * @throws GuzzleException
     * @throws NotFoundExceptionInterface
     */
    public static function renewShopContractNotify(array $decodeData, OpenShopUserContractModel $userContractModel)
    {
        switch ($decodeData["callbackType"]) {
            case ContractStatusEnum::CALL_BACK_TYPE_COMPLETE:
                switch ($decodeData["contractStatus"]) {
                    case ContractStatusEnum::COMPLETE:
                        if (!$userContractModel->signTime) {
                            //转储合同文件
                            self::transSave($decodeData["contractId"]);
                            //更新三方合同签约状态
                            OpenShopUserExtContractModel::query()
                                                        ->where("contractId", $userContractModel->id)
                                                        ->update(["signStatus" => 1, "signTime" => time()]);

                            //更新续签单工单状态
                            RenewOrderService::finishRenewFlowOrder($userContractModel);

                            //更新合同主表状态
                            $userContractModel->signTime     = time();
                            $userContractModel->detailStatus = ContractStatusEnum::COMPLETE;
                            $userContractModel->save();

                            //系统日志
                            ChangeSupport::getInstance()->buildInsertChanges("续签合同签署");
                            ChangeSupport::getInstance()->batchChangesWriteToOrderLog(
                                $userContractModel->signOrderRel->id,
                                OpenShopSignOrderLogModel::INVALID_ORDER_CONTRACT_SIGN,
                                $userContractModel->signOrderRel->identityCardRel->name
                            );
                        }
                        break;
                    default:
                        break;
                }
                break;
        }

    }

    /**
     * 解约合同回调处理方法
     *
     * @param array $decodeData
     * @param OpenShopUserContractModel $userContractModel
     * @throws ContainerExceptionInterface
     * @throws GuzzleException
     * @throws NotFoundExceptionInterface
     */
    public static function cancelShopContractNotify(array $decodeData, OpenShopUserContractModel $userContractModel)
    {
        //解约
        switch ($decodeData["callbackType"]) {
            case ContractStatusEnum::CALL_BACK_TYPE_COMPLETE:
                Artisan::call(
                    "openShop:del-order",
                    [
                        "orderNo"  => $userContractModel->orderNo,
                        "delAll"   => 0
                    ]
                );

                //转储合同文件
                self::transSave($decodeData["contractId"]);
                //更新三方合同签约状态
                OpenShopUserExtContractModel::query()
                                            ->where("contractId", $userContractModel->id)
                                            ->update(["signStatus" => 1, "signTime" => time()]);

                //更新合同主表状态
                $userContractModel->detailStatus = ContractStatusEnum::COMPLETE;
                $userContractModel->save();

                if ($userContractModel->signOrderRel->shopCode > 0) {
                    //rms闭店
                    RmsShopRemote::closeShop($userContractModel->signOrderRel->shopCode);
                }

                //系统日志
                ChangeSupport::getInstance()->buildInsertChanges("作废合同签署");
                ChangeSupport::getInstance()->batchChangesWriteToOrderLog(
                    $userContractModel->signOrderRel->id,
                    OpenShopSignOrderLogModel::INVALID_ORDER_CONTRACT_SIGN,
                    $userContractModel->signOrderRel->identityCardRel->name
                );
                break;
        }
    }

    /**
     * 新店加盟回调处理方法
     *
     * @param array $decodeData
     * @param OpenShopUserContractModel $userContractModel
     * @throws ContainerExceptionInterface
     * @throws GuzzleException
     * @throws NotFoundExceptionInterface
     */
    public static function newShopContractNotify(array $decodeData, OpenShopUserContractModel $userContractModel)
    {
        switch ($decodeData["callbackType"]) {
            case ContractStatusEnum::CALL_BACK_TYPE_COMPLETE:
                //合同签约完成
                switch ($decodeData["contractStatus"]) {
                    case ContractStatusEnum::COMPLETE:
                        if (isset($decodeData['bizId'])) {
                            $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($decodeData["contractId"]);
                            $signOrder         = $userContractModel->signOrderRel;

                            //更新合同主表状态
                            $userContractModel->detailStatus = ContractStatusEnum::COMPLETE;
                            $userContractModel->signTime     = time();
                            $userContractModel->save();

                            if ($signOrder->step < SignOrderEnum::STEP_5) {
                                self::updateExtContractStatusAndGenerateShop(
                                    $signOrder->orderNo,
                                    ContractStatusEnum::CODE_NUM[$decodeData['contractStatus']],
                                    $decodeData['contractId']
                                );

                            } else {
                                //转存合同
                                UserExtContractService::transSave($decodeData['contractId']);
                                //获取主订单id
                                $userContractModel = OpenShopUserContractModel::getUserContractByContractExtNo($decodeData['contractId']);
                                //根据contractId 修改状态
                                OpenShopUserExtContractModel::updateByContractId(
                                    $userContractModel->id,
                                    ContractStatusEnum::CODE_NUM[$decodeData['contractStatus']]
                                );

                                $invalidContract = OpenShopUserContractModel::query()
                                                                            ->where("orderNo", $signOrder->orderNo)
                                                                            ->where("detailStatus",
                                                                                ContractStatusEnum::COMPLETE)
                                                                            ->where("contractStatus",
                                                                                OpenShopUserContractModel::CONTRACT_STATUS_INVALID)
                                                                            ->orderBy("id", "desc")
                                                                            ->first();

                                if ($invalidContract && $invalidContract->contractExtNo) {
                                    try {
                                        UserExtContractService::invalidContract($invalidContract->contractExtNo);
                                    } catch (Exception $exception) {

                                    }
                                }

                                //修改远程门店手机号
                                $contact = $signOrder->identityCardRel->name;
                                RmsShopRemote::updateShopMobile($signOrder->shopCode, $signOrder->baseInfoRel->mobile,
                                    $contact);
                            }
                            //签约阶段-在「商家开店合同签署」完成之后，进行推送 评价消息
                            $rmsShop = (new RmsShopApi())->getShopByCode($signOrder->shopCode);
                            if ($rmsShop['code']) {
                                $shopId = $rmsShop['data']['id'];
                                NotifyService::notify($signOrder->orderNo, AppraiseModel::TYPE_OPENSHOP_SIGN, 0,
                                    $shopId);
                            }
                        }
                        break;
                }
                break;
            case ContractStatusEnum::CALL_BACK_TYPE_INVALIDING:
                switch ($decodeData["contractStatus"]) {
                    case ContractStatusEnum::INVALIDED:
                        $invalidatedClosure = function () use ($userContractModel) {
                            $userContractModel->isDeleted = 1;
                            $userContractModel->save();

                            //契约锁合同更新签约信息
                            OpenShopUserExtContractModel::query()->where("contractId", $userContractModel->id)
                                                        ->update([
                                                            "signStatus" => 1,
                                                            "signTime"   => time()
                                                        ]);

                            //更新合同状态为正常
                            $signOrder = $userContractModel->signOrderRel;
                            if ($signOrder && $signOrder->contractStatus != OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL) {
                                //更新合同状态为正常
                                OpenShopSignOrderModel::query()
                                                      ->where("orderNo", $signOrder->orderNo)
                                                      ->update([
                                                          "contractStatus" => OpenShopSignOrderModel::CONTRACT_STATUS_NORMAL
                                                      ]);
                            }
                        };
                        $invalidatedClosure();
                        break;
                }
                break;
        }
    }

}
